package com.ape.mapsa.common;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.persistence.PostLoad;

import org.apache.log4j.Logger;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.MenuModel;

import com.ape.mapsa.bpm.service.ProductionHelper;
import com.ape.mapsa.common.constants.TipoMaterial;
import com.ape.mapsa.produccion.model.DepItemPrintSpec;
import com.ape.mapsa.produccion.model.Item;
import com.ape.mapsa.produccion.model.ItemTipo;
import com.ape.mapsa.produccion.model.Muestra;
import com.ape.mapsa.produccion.service.IProduccionService;

@ManagedBean(name = "itemsMB")
@ViewScoped
public class ItemsBean extends BeanCRUD implements Serializable {

	private static final long serialVersionUID = -1865358477053230245L;

	private static final Logger log = Logger.getLogger(ItemsBean.class);

	@ManagedProperty(value = "#{produccionService}")
	private IProduccionService prodService;

	@ManagedProperty(value = "#{userMB}")
	private UserBean userBean;

	@ManagedProperty(value = "#{colorsMB}")
	private ColorsBean colorsBean;
	@ManagedProperty(value = "#{muestrasMB}")
	private MuestrasBean muestrasBean;

	private List<Item> items;
	private List<Item> itemsFiltrados = new ArrayList<Item>();
	private Item selectedItem = null;
	private SelectItem[] itemTipos;
	private boolean rowSelected = false;

	private boolean showAbm = false;

	private Item newItem;

	private TipoMaterial[] tiposMaterial;
	private TipoMaterial tipoMaterialSeleccionado;

	private List<ItemTipo> tiposProd;

	private Item result;

	private boolean newItemDuplicado;

	private String optionPesoEspesor = "";
	private boolean editing = false;

	private String title;

	private Integer pesoEspesorOption = new Integer(1);

	private Long selectedId;

	@PostConstruct
	public void initialize() {
		log.info("Initializing ITEMS BEAN");
		newItem = new Item();
		newItem.setDepItemPrintSpec(new DepItemPrintSpec());
		items = new ArrayList<Item>();

		setItems(prodService.getAllItems());

		itemsFiltrados.addAll(items);
		List<ItemTipo> allItemTipos = prodService.getAllItemTipos();
		createTipoFilterOptions(allItemTipos);
		setTiposMaterial(TipoMaterial.values());
		setTiposProd(allItemTipos);
	}

	public void editarItem(ActionEvent actionEvent) {
		log.info("Editando Item " + selectedItem);
		newItem = selectedItem;
		if (newItem != null) {
			editing = true;
		}
	}

	public void pesoEspesorChanged() {
		log.debug("peso espesor changed to: " + pesoEspesorOption);
	}

	public void saveItem(ActionEvent actionEvent) {
		FacesContext context = FacesContext.getCurrentInstance();
		log.info("Updating: " + newItem);
		setNonstraightVariables();
		convertPesoEspesor();
		try {
			prodService.updateItem(newItem);
			resetItem();
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, newItem.getCodigo(), "Fue guardado satisfactoriamente");
			context.addMessage("addMuestraForm:addMessages", msg);
		} catch (Exception ex) {
			ex.printStackTrace();
			FacesMessage exceptionEnGuardar = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "El item no pudo ser guardado.");
			context.addMessage("addMuestraForm:addMessages", exceptionEnGuardar);
		}
		newItem = new Item();
		editing = false;
	}

	public void resetItem() {
		log.info("Reseting item data");
		newItem = new Item();
		editing = false;
		showAbm = false;
	}

	private void createTipoFilterOptions(List<ItemTipo> allItemTipos) {
		itemTipos = new SelectItem[allItemTipos.size() + 1];
		itemTipos[0] = new SelectItem("", "Seleccionar");
		int i = 1;
		for (ItemTipo itemTipo : allItemTipos) {
			itemTipos[i] = new SelectItem(itemTipo, itemTipo.getDescripcion());
			i++;
		}
	}

	public void rowSelected(SelectEvent event) {
		log.debug("rowSelected" + selectedItem);
		setRowSelected(selectedItem != null);
		result = selectedItem;
	}

	public void getItem(ActionEvent actionEvent) {
		result = selectedItem;
	}

	@PostLoad
	public void postload() {
		log.info("ITEMS BEAN BEAN LOADED");
	}

	public void addNewItem(ActionEvent actionEvent) {
		newItem.setItemState(ProductionHelper.NEW_ITEM);
		saveItem();
	}

	public void addItem() {
		log.debug("listening add item");
		newItem.setItemState(ProductionHelper.ACTIVE_ITEM);
		saveItem();
	}

	private void saveItem() {
		FacesContext context = FacesContext.getCurrentInstance();
		checkItemDuplicado(context);
		setNonstraightVariables();
		log.debug("Saving Item");
		// Set item code if new
		if (newItem.getCodigo() == null) {
			log.info("geting new items code");
			String lastItemId = "N00000000";
			for (Item item : getItems()) {
				if (item.getItemState() == ProductionHelper.NEW_ITEM || item.getItemState() == ProductionHelper.REJECTED_ITEM) {
					if (item.getCodigo().compareTo(lastItemId) > 0) {
						lastItemId = item.getCodigo();
					}
				}
			}
			log.debug("last item code: " + lastItemId);
			Integer nextItemCode = Integer.parseInt(lastItemId.replace("N", "")) + 1;
			String format = "%0" + (8 - nextItemCode.toString().length()) + "d";
			String newItemCode = "N" + String.format(format, nextItemCode);

			log.debug("new item code: " + newItemCode);

			newItem.setCodigo(newItemCode);
		}

		try {
			prodService.saveDepItemPrintSpces(newItem.getDepItemPrintSpec());

			convertPesoEspesor();

			prodService.saveItem(newItem);
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, newItem.getCodigo(), "Fue guardado satisfactoriamente");
			context.addMessage("addMuestraForm:addMessages", msg);
			itemsFiltrados.add(newItem);
			items.add(newItem);
			showAbm = false;
		} catch (Exception ex) {
			ex.printStackTrace();
			FacesMessage exceptionEnGuardar = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "El item no pudo ser guardado.");
			context.addMessage("addMuestraForm:addMessages", exceptionEnGuardar);
		}
	}

	private void convertPesoEspesor() {
		float A = newItem.getAncho() * 0.02f;
		float L = newItem.getLargo() / 100;
		if (pesoEspesorOption == 1) {
			// espesor especificado
			// sacar peso apartir del espesor esto es facil

			float grxm2 = newItem.getEspesor() * newItem.getDensidad();
			float gramaje = A * grxm2;
			float peso = gramaje * L;
			newItem.setPeso(peso);
		} else {
			float espesor = newItem.getPeso() / (A * newItem.getDensidad() * L);
			newItem.setEspesor(espesor);
		}
	}

	private void checkItemDuplicado(FacesContext context) {
		if (newItem.getCodigo() != null) {
			for (Item item : items) {
				if (newItem.getCodigo().equals(item.getCodigo())) {
					RequestContext requestContext = RequestContext.getCurrentInstance();
					requestContext.addCallbackParam("isValid", false);
					FacesMessage codigoDuplicado = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "Codigo de Item duplicado.");
					context.addMessage(null, codigoDuplicado);
					setNewItemDuplicado(true);
					return;
				}
			}
			setNewItemDuplicado(false);
		}
	}

	private void setNonstraightVariables() {
		newItem.setDensidad(tipoMaterialSeleccionado.getValor());
		log.info("Guardando Item" + newItem);
		for (ItemTipo tipoItem : tiposProd) {
			if (newItem.getItemTipo().getDescripcion().equals(tipoItem.getDescripcion())) {
				newItem.setItemTipo(tipoItem);
				break;
			}
		}

		List<Muestra> muestras = muestrasBean.getMuestras();
		for (Muestra muestra : muestras) {
			if (newItem.getMuestraBean() != null && newItem.getMuestraBean().getName().equals(muestra.getName())) {
				newItem.setMuestraBean(muestra);
				break;
			}
		}
	}

	public void getResultMuestra() {
		Muestra result2 = muestrasBean.getResult();
		log.info("Getting result from muestra " + result2);
		newItem.setMuestraBean(result2);
	}

	public void getResultColor() {
		log.info("Getting result from colors");
		newItem.setColorBean(colorsBean.getResult());
	}

	@PreDestroy
	public void predestroy() {
		log.info("ITEMS BEAN BEAN IS GOING TO BE DESTROYED");
	}

	public Item getSelectedItem() {
		return selectedItem;
	}

	public void setSelectedItem(Item selectedItem) {
		this.selectedItem = selectedItem;
	}

	public SelectItem[] getItemTipos() {
		return itemTipos;
	}

	public List<Item> getItemsFiltrados() {
		return itemsFiltrados;
	}

	public void setItemsFiltrados(List<Item> itemsFiltrados) {
		this.itemsFiltrados = itemsFiltrados;
	}

	public boolean isRowSelected() {
		return rowSelected;
	}

	public void setRowSelected(boolean rowSelected) {
		this.rowSelected = rowSelected;
	}

	public Item getResult() {
		return result;
	}

	public void setResult(Item result) {
		this.result = result;
	}

	public Item getNewItem() {
		return newItem;
	}

	public void setNewItem(Item newItem) {
		this.newItem = newItem;
	}

	public TipoMaterial[] getTiposMaterial() {
		return tiposMaterial;
	}

	public void setTiposMaterial(TipoMaterial[] tiposMaterial) {
		this.tiposMaterial = tiposMaterial;
	}

	public TipoMaterial getTipoMaterialSeleccionado() {
		return tipoMaterialSeleccionado;
	}

	public void setTipoMaterialSeleccionado(TipoMaterial tipoMaterialSeleccionado) {
		this.tipoMaterialSeleccionado = tipoMaterialSeleccionado;
	}

	public List<ItemTipo> getTiposProd() {
		return tiposProd;
	}

	public void setTiposProd(List<ItemTipo> tiposProd) {
		this.tiposProd = tiposProd;
	}

	public ColorsBean getColorsBean() {
		return colorsBean;
	}

	public void setColorsBean(ColorsBean colorsBean) {
		this.colorsBean = colorsBean;
	}

	public IProduccionService getProdService() {
		return prodService;
	}

	public void setProdService(IProduccionService prodService) {
		this.prodService = prodService;
	}

	public List<Item> getItems() {
		return items;
	}

	public void setItems(List<Item> items) {
		this.items = items;
	}

	public MuestrasBean getMuestrasBean() {
		return muestrasBean;
	}

	public void setMuestrasBean(MuestrasBean muestrasBean) {
		this.muestrasBean = muestrasBean;
	}

	public boolean isNewItemDuplicado() {
		return newItemDuplicado;
	}

	public void setNewItemDuplicado(boolean newItemDuplicado) {
		this.newItemDuplicado = newItemDuplicado;
	}

	public boolean isEditing() {
		return editing;
	}

	public void setEditing(boolean editing) {
		this.editing = editing;
	}

	public String getOptionPesoEspesor() {
		return optionPesoEspesor;
	}

	public void setOptionPesoEspesor(String optionPesoEspesor) {
		this.optionPesoEspesor = optionPesoEspesor;
	}

	@Override
	public void save(ActionEvent event) {
		saveItem(event);
		RequestContext.getCurrentInstance().update("addItemForm:abm_id");
		RequestContext.getCurrentInstance().update("addItemForm:items:items");
	}

	@Override
	public void update(ActionEvent event) {
	}

	@Override
	public void create(ActionEvent event) {
		log.info("Articulo nuevo");
		newItem = new Item();
		log.debug("item reseted: " + newItem);
		showAbm = true;
		editing = false;
		RequestContext.getCurrentInstance().update("addItemForm:abm_id");
	}

	@Override
	public void edit(ActionEvent event) {
		if (selectedItem != null && selectedItem.getId() != null) {
			log.info("Editando Item " + selectedItem);
			newItem = selectedItem;
			showAbm = true;
			selectedId = selectedItem.getId();
			if (newItem != null) {
				editing = true;
			}
			RequestContext.getCurrentInstance().update("addItemForm:abm_id");
			RequestContext.getCurrentInstance().scrollTo("addItemForm:abm_id");
		} else {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Desactivación",
					"Debe seleccionar una formula para realizar esta operación");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}

	}

	@Override
	public void delete(ActionEvent event) {
		// TODO Auto-generated method stub
	}

	@Override
	public MenuModel getMenuModel() {
		return menuModel;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public boolean isShowAbm() {
		return showAbm;
	}

	public void setShowAbm(boolean showAbm) {
		this.showAbm = showAbm;
	}

	public UserBean getUserBean() {
		return userBean;
	}

	public void setUserBean(UserBean userBean) {
		this.userBean = userBean;
	}

	public Integer getPesoEspesorOption() {
		return pesoEspesorOption;
	}

	public void setPesoEspesorOption(Integer pesoEspesorOption) {
		this.pesoEspesorOption = pesoEspesorOption;
	}

}
